package com.onion.kit.ext.aliyun.oss;

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.common.utils.StringUtils;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.PutObjectResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

public class OssClientSdk {

    private Logger logger = LoggerFactory.getLogger(OssClientSdk.class);

    private static String USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36";

    private String endpoint;
    private String accessKeyId;
    private String accessKeySecret;
    private String defaultBucket;

    public OssClientSdk(){}

    public OssClientSdk(String endpoint, String accessKeyId, String accessKeySecret){
        this.endpoint = endpoint;
        this.accessKeyId = accessKeyId;
        this.accessKeySecret = accessKeySecret;
    }

    public void setDefaultBucket(String defaultBucket){
        this.defaultBucket = defaultBucket;
    }

    /**
     * 获取OssClient[外部调用，必须要自行完成资源释放]
     * @return
     */
    public OSS getOssClient(){
        return new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
    }

    /**
     * 上传本地文件至阿里云OSS
     * @param bucket
     * @param objectPath
     * @param objectName
     * @param localFile
     * @return
     */
    public String uploadFile(String bucket, String objectPath, String objectName, String localFile){
        if(StringUtils.isNullOrEmpty(bucket)){
            throw new RuntimeException("[OSS UploadFile]Aliyun bucket为空!");
        }
        if(StringUtils.isNullOrEmpty(objectPath)){
            throw new RuntimeException("[OSS UploadFile]Aliyun objectPath为空!");
        }
        if(StringUtils.isNullOrEmpty(objectName)){
            throw new RuntimeException("[OSS UploadFile]Aliyun objectName为空!");
        }

        String filePath;
        if(!objectPath.endsWith("/") && !objectPath.startsWith("/")){
            filePath = String.format("%s/%s", objectPath, objectName);
       }else{
            filePath = String.format("%s%s", objectPath, objectName);
        }

        this.uploadFile(bucket, filePath, localFile);
        return filePath;
    }

    /**
     * 上传本地文件至阿里云OSS
     * @param bucket
     * @param fullPath
     * @param localFile
     */
    public void uploadFile(String bucket, String fullPath, String localFile){
        OSS ossClient = this.getOssClient();
        try {
            this.uploadFile(ossClient, bucket, fullPath, localFile);
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

    /**
     * 上传文件至阿里云OSS【ossClient需要调用方自行释放】
     * @param ossClient
     * @param bucket
     * @param fullPath
     * @param localFile
     */
    public void uploadFile(OSS ossClient, String bucket, String fullPath, String localFile){
        InputStream inputStream = null;
        boolean hasError = false;
        try {
            inputStream = new FileInputStream(localFile);
        } catch (FileNotFoundException e) {
            hasError = true;
            throw new RuntimeException(String.format("[OSS UploadFile]本地文件未找到：%s", localFile));
        }finally {
            if(hasError && inputStream != null){
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        //创建PutObject请求
        PutObjectResult result = this.doUploadOSS(ossClient, bucket, fullPath, inputStream);
        if(result.getResponse().getStatusCode() == 200){
            logger.info("[OSS UploadFile]上传文件成功: localFile={}, bucket={}, ossFile={}", localFile, bucket, fullPath);
        }else{
            logger.error("[OSS UploadFile]上传文件失败: localFile={}", localFile, result.getResponse().getErrorResponseAsString());
        }
    }


    /**
     * 上传网络文件至阿里云OSS
     * @param bucket
     * @param ossPath
     * @param fileName
     * @param srcFileUrl
     */
    public void uploadFileByUrl(String bucket, String ossPath, String fileName, String srcFileUrl){
        InputStream inputStream = null;
        HttpURLConnection conn = null;
        boolean hasError = false;
        try {
            URL url = new URL(srcFileUrl);
            conn = (HttpURLConnection) url.openConnection();
            conn.setConnectTimeout(3 * 1000);
            //防止屏蔽程序抓取而返回403错误
            conn.setRequestProperty("User-Agent", USER_AGENT);
            //得到网络文件输入流
            inputStream = conn.getInputStream();
        } catch (Exception e) {
            hasError = true;
            throw new RuntimeException(e);
        } finally {
            if(hasError){
                if(conn != null){
                    conn.disconnect();
                }
                if(inputStream != null){
                    try {
                        inputStream.close();
                    } catch (IOException ex) {
                        ex.printStackTrace();
                    }
                }
                return;
            }
        }


        String fullPath;
        if(!ossPath.endsWith("/") && !fileName.startsWith("/")){
            fullPath = String.format("%s/%s", ossPath, fileName);
        }else{
            fullPath = String.format("%s%s", ossPath, fileName);
        }

        OSS ossClient = this.getOssClient();
        try{
            PutObjectResult result = this.doUploadOSS(ossClient, bucket, fullPath, inputStream);
            if(result.getResponse().getStatusCode() == 200){
                logger.info("[OSS UploadFile]上传文件成功: srcFile={}, bucket={}, ossFile={}", srcFileUrl, bucket, fullPath);
            }else{
                logger.error("[OSS UploadFile]上传文件失败: srcFile={}", srcFileUrl, result.getResponse().getErrorResponseAsString());
            }
        }finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }


    private PutObjectResult doUploadOSS(OSS ossClient, String bucket, String fullPath, InputStream inputStream) {
        PutObjectRequest putObjectRequest = new PutObjectRequest(bucket, fullPath, inputStream);
        // 设置该属性可以返回response; 如果不设置，则返回的response为空
        putObjectRequest.setProcess("true");
        // 创建PutObject请求
        return ossClient.putObject(putObjectRequest);
    }

}